#pragma once
#include <sstream>
#include <v8.h>
#include <memory>
#include <node_object_wrap.h>
#include "../client.h"
#include "parson.h"
#ifdef _WIN32
#include <corecrt_io.h>
#include <Shlwapi.h>
#define ACCESS _waccess 
#define MKDIR(a) _wmkdir((a))
#else 
#define MKDIR(a) mkdir((a),0755)
#endif
#ifdef __linux__ || __APPLE__
#define ACCESS access 
#include <iconv.h> 
#include <sys/wait.h>
#include <sys/types.h>
#endif
namespace privacy_service
{
bool isUser(const int64);
bool isGroup(const int64);
bool isApp(const int64);
//转换

std::string GBK_2_UTF8(std::string gbkStr);
void ConvertUtf8ToGBK(std::string&amp, std::string strUtf8);
#ifdef _WIN32
const std::wstring s2ws(const std::string& s);
std::string WcharToChar(const wchar_t* wp, size_t m_encode = CP_ACP);
std::wstring SToWS(const std::string &s);
std::string Utf8ToGbk(const char *src_str);
BOOL GetDirSize(LPWSTR lpsPath);
void createProcessAndWait(std::string path, std::string param);
std::string findWindowsAppUninstallPath(const char * dir);
std::string getWindowsAppPath(bool isInstallPath, std::string appName);
std::string searchWindowsAppPath(HKEY key, bool isInstallPath, std::string appName);
LONG GetSoftSign(std::string path, char * v_pszSign, int v_iBufSize);
#endif
//运行其他应用
void bigDataControl(std::string path, std::string param);
//开机自启
#define REG_HKEY_PATH "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
#define REG_HKEY_KEY "Linkdood"
std::string getRegValue();
bool deleteRegValue();
bool setRegValue();
//系统空闲
bool isSystemIdle();
//windowsApp相关
//文件操作
int creatDir(char *pDir);
int remove_Dir(const char* dirPath);
	//	字符串和其他类型互转函数
	template<class T>
	T convertFromString(const std::string& s) {
		T val;
		if (s == "") {
			std::stringstream ss("0");
			ss >> val;
		}
		else {
			std::stringstream ss(s);
			ss >> val;
		}
		return val;
	}

	template<class T>
	std::string convertToString(T val) {
		std::stringstream ss;
		ss << val;
		return ss.str();
	}
	int getProcessCount(std::string name, bool onlyJudgeRunning);
}

namespace privacy_service
{
using PersistentPtr = std::shared_ptr<v8::Global<v8::Function> >;
class Client;
}
//生成回调数据 rep和jsObject  设置通用返回数据code len = 0为不进行数据校验   
#define MAKE_DATA()							\
/*	if (len != 0 && sizeof(respType) != len)					\
		printf("数据长度不一致\n");								\
	respType *rep = (respType*)data;	*/						\
	auto isolate = v8::Isolate::GetCurrent();					\
	v8::HandleScope scope(isolate);								\
	Local<Object> jsObject = Object::New(isolate);				\
	//Helper::toJsNumber(jsObject, "code", (double)code)
#define MAKE_BACKMSG()						\
	char* msgTempJson = json_serialize_to_string(pJson); \
	backMsg = msgTempJson; \
	json_free_serialized_string(msgTempJson); \
	json_value_free(pJson);
#define GET_ISOlATE()						\
	v8::Isolate* isolate = args.GetIsolate(); \
  v8::HandleScope handle_scope(isolate);   \
//数据转换帮助类
class Helper
{
public:
	/*************************通知处理函数*******************************/

	/********通过local<Function>获取persistent<Function>对象**********/
	static std::shared_ptr<v8::Global<v8::Function> > persistentFunc(v8::Local<v8::Value> local)
	{
		if (local->IsUndefined() || !local->IsFunction())
			return nullptr;

		v8::Local<v8::Function> cb = v8::Local<v8::Function>::Cast(local);
		return std::make_shared< v8::Global<v8::Function> >(cb->GetIsolate(), cb);
	}

	/********把std::shared_ptr<v8::Global<v8::Function> >转换为local<Function>,并调用**********/
	static void callJsCallback(v8::Isolate *isolate, std::shared_ptr<v8::Global<v8::Function> > persistent, v8::Local<v8::Object> &jsObject)
	{
		if (persistent == nullptr)
			return;

		const int argc = 1;
		v8::Local<v8::Value> argv[argc];
		argv[0] = jsObject;
		auto cb = v8::Local<v8::Function>::New(isolate, *persistent.get());
#ifdef NODE_12
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		cb->Call(context, Null(isolate),argc, argv);
#elif defined(ELECTRON_8)
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		cb->Call(context, jsObject, argc, argv);
#else
		cb->Call(Null(isolate), argc, argv);
#endif
	}
	static void callJsCallback(v8::Isolate *isolate, std::shared_ptr<v8::Global<v8::Function> > persistent, v8::Local<v8::String> &jsString)
	{
		if (persistent == nullptr)
			return;

		const int argc = 1;
		v8::Local<v8::Value> argv[argc];
		argv[0] = jsString;
		auto cb = v8::Local<v8::Function>::New(isolate, *persistent.get());
#ifdef NODE_12
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		cb->Call(context, Null(isolate), argc, argv);
#elif defined(ELECTRON_8)
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		cb->Call(context, jsString, argc, argv);
#else
		cb->Call(Null(isolate), argc, argv);
#endif
	}

	/********生成javascript service对象实例，作为返回值返回给js调用者**********/
	//包装对象的工厂
    //避免显式地使用 JavaScript 的 new 操作来创建对象实例
	template<typename T>
	static void buildService(const v8::FunctionCallbackInfo<v8::Value> &args, T &constructor)
	{
		v8::Isolate* isolate = args.GetIsolate();

		privacy_service::Client* client = node::ObjectWrap::Unwrap<privacy_service::Client>(args.Holder());
		const int argc = 1;
		v8::Local<v8::Value> argv[argc] = { v8::External::New(isolate, client->channel()) };

		v8::Local<v8::Function> cons = v8::Local<v8::Function>::New(isolate, constructor);
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		v8::Local<v8::Object> instance = cons->NewInstance(context, argc, argv).ToLocalChecked();

		args.GetReturnValue().Set(instance);
	}

	static v8::Local<v8::Value> getValueFromObj(v8::Local<v8::Object> &jsObj, const char *key)
	{
		v8::Isolate *isolate = jsObj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		return jsObj->Get(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked()).ToLocalChecked();
#else
		return jsObj->Get(v8::String::NewFromUtf8(isolate, key));
#endif
	}
	/*********************把c++数据转换为相应的js类型*******************************/
	static void toJsBool(v8::Local<v8::Object> &jsObj, const char *key, bool value)
	{
		v8::Isolate *isolate = jsObj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		//v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, key).ToLocalChecked();
		//v8::MaybeLocal<v8::Script> script = v8::Script::Compile(context, source);
		jsObj->Set(context, v8::String::NewFromUtf8(isolate, key).ToLocalChecked(), v8::Boolean::New(isolate, value));
#else
		jsObj->Set(v8::String::NewFromUtf8(isolate, key), v8::Boolean::New(isolate, value));
#endif
	}

	static void toJsNumber(v8::Local<v8::Object> &jsObj, const char *key, double value)
	{
		v8::Isolate *isolate = jsObj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		jsObj->Set(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked(), v8::Number::New(isolate, value));
#else
		jsObj->Set(v8::String::NewFromUtf8(isolate, key), v8::Number::New(isolate, value));
#endif
	}

	static void toJsString(v8::Local<v8::Object> &jsObj, const char *key, const char *value)
	{
		v8::Isolate *isolate = jsObj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		jsObj->Set(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked(), v8::String::NewFromUtf8(isolate, value).ToLocalChecked());
#else
		jsObj->Set(v8::String::NewFromUtf8(isolate, key), v8::String::NewFromUtf8(isolate, value));
#endif
	}
	static void toJsStrArray(JSON_Object* root_object, const char *key, const std::vector<std::string> &vec)
	{
		JSON_Value * aryVal = json_value_init_array();
		JSON_Array * ary = json_value_get_array(aryVal);
		for (auto i : vec) json_array_append_string(ary, i.c_str());
		json_object_set_value(root_object, key, aryVal);
	}
	static void toJsStrArray(v8::Local<v8::Object> &jsObj, const char *key, const std::vector<std::string> &vec)
	{
		v8::Isolate *isolate = jsObj->GetIsolate();
		v8::Local<v8::Array> arr = v8::Array::New(isolate);
		for (uint32_t i = 0; i < vec.size(); ++i)
		{
#ifdef ELECTRON_8
			v8::Local<v8::Context> context = isolate->GetCurrentContext();
			arr->Set(context,i, v8::String::NewFromUtf8(isolate, vec[i].c_str()).ToLocalChecked());
#else
			arr->Set(i, v8::String::NewFromUtf8(isolate, vec[i].c_str()));
#endif
		}
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		jsObj->Set(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked(), arr);
#else
		jsObj->Set(v8::String::NewFromUtf8(isolate, key), arr);
#endif
	}
	template<typename T>
	static void toJsNumArray(JSON_Object* root_object, const char *key, const std::vector<T> &vec)
	{
		JSON_Value * aryVal = json_value_init_array();
		JSON_Array * ary = json_value_get_array(aryVal);
		for (auto i : vec) json_array_append_number(ary, i);
		json_object_set_value(root_object, key, aryVal);
	}
	template<typename T>
	static void toJsLongLongArray(JSON_Object* root_object, const char *key, const std::vector<T> &vec)
	{
		JSON_Value * aryVal = json_value_init_array();
		JSON_Array * ary = json_value_get_array(aryVal);
		for (auto i : vec) json_array_append_string(ary, privacy_service::convertToString(i).c_str());
		json_object_set_value(root_object, key, aryVal);
	}
	template<typename T>
	static void toJsNumVector(v8::Local<v8::Object> &jsObj, const char *key, const std::vector<T> &vec)
	{
		v8::Isolate *isolate = jsObj->GetIsolate();
		v8::Local<v8::Array> arr = v8::Array::New(isolate);
		for (uint32_t i = 0; i < vec.size(); ++i)
		{
#ifdef ELECTRON_8
			v8::Local<v8::Context> context = isolate->GetCurrentContext();
			arr->Set(context, i, v8::Number::New(isolate, (double)vec[i]));
#else
			arr->Set(i, v8::Number::New(isolate, (double)vec[i]));
#endif
		}
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		//v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, key).ToLocalChecked();
		//v8::MaybeLocal<v8::Script> script = v8::Script::Compile(context, source);
		jsObj->Set(context, v8::String::NewFromUtf8(isolate, key).ToLocalChecked(), arr);
#else
		jsObj->Set(v8::String::NewFromUtf8(isolate, key), arr);
#endif
	}
	
	/*********************把js数据转换为相应的c++类型*******************************/


	static std::string toCppString(v8::Isolate *isolate,const v8::Local<v8::Value> &jsValue)
	{
		if (jsValue->IsUndefined() || !jsValue->IsString())
			return "";

		v8::Local<v8::String> lStr = v8::Local<v8::String>::Cast(jsValue);
#ifdef NODE_12
		v8::String::Utf8Value utfValue(isolate,lStr);
#else
		v8::String::Utf8Value utfValue(lStr);
#endif
		return std::string(*utfValue);
	}

	static bool toCppBool(v8::Isolate *isolate,const v8::Local<v8::Value> &jsValue)
	{
		if (jsValue->IsUndefined() || !jsValue->IsBoolean())
			return false;

		v8::Local<v8::Boolean> b = v8::Local<v8::Boolean>::Cast(jsValue);
#ifdef NODE_12
		return b->BooleanValue(isolate);
#else
		return b->BooleanValue();
#endif
	}

	static double toCppNumber(v8::Isolate *isolate, const v8::Local<v8::Value> &jsValue)
	{
		if (jsValue->IsUndefined() || !jsValue->IsNumber())
			return 0;

		v8::Local<v8::Number> jsNum = v8::Local<v8::Number>::Cast(jsValue);
#ifdef NODE_12
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		return jsNum->NumberValue(context).ToChecked();
#else
		return jsNum->NumberValue();
#endif
	}

	static std::string toCppStringFromObj(const v8::Local<v8::Object> &obj, const char *key)
	{
		v8::Isolate *isolate = obj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		auto value = obj->Get(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked());
		return toCppString(isolate, value.ToLocalChecked());
#else
		auto value = obj->Get(v8::String::NewFromUtf8(isolate, key));
		return toCppString(isolate, value);
#endif
	}

	static double toCppNumberFromObj(const v8::Local<v8::Object> &obj, const char *key)
	{
		v8::Isolate *isolate = obj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		auto value = obj->Get(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked());
		return toCppNumber(isolate, value.ToLocalChecked());
#else
		auto value = obj->Get(v8::String::NewFromUtf8(isolate, key));
		return toCppNumber(isolate, value);
#endif
	}

	static bool toCppBooleanFromObj(const v8::Local<v8::Object> &obj, const char *key)
	{
		v8::Isolate *isolate = obj->GetIsolate();
#ifdef ELECTRON_8
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		auto value = obj->Get(context,v8::String::NewFromUtf8(isolate, key).ToLocalChecked());
		return toCppBool(isolate, value.ToLocalChecked());
#else
		auto value = obj->Get(v8::String::NewFromUtf8(isolate, key));
		return toCppBool(isolate, value);
#endif
	}

	template<typename T>
	static bool toCppLongLongVector(std::vector<T> &vec, const v8::Local<v8::Value> &jsValue)
	{
		if (jsValue->IsUndefined() || !jsValue->IsArray())
			return false;

		v8::Local<v8::Array> jsArray = v8::Local<v8::Array>::Cast(jsValue);
		v8::Isolate *isolate = jsArray->GetIsolate();
		for (uint32_t i = 0; i < jsArray->Length(); ++i)
		{
#ifdef ELECTRON_8
			v8::Local<v8::Context> context = isolate->GetCurrentContext();
			std::string str = toCppString(isolate, jsArray->Get(context,i).ToLocalChecked());
#else
			std::string str = toCppString(isolate, jsArray->Get(i));
#endif
			vec.push_back(privacy_service::convertFromString<T>(str));
		}
		return true;
	}

	template<typename T>
	static bool toCppNumVector(std::vector<T> &vec, const v8::Local<v8::Value> &jsValue)
	{
		if (jsValue->IsUndefined() || !jsValue->IsArray())
			return false;

		v8::Local<v8::Array> jsArray = v8::Local<v8::Array>::Cast(jsValue);
		v8::Isolate *isolate = jsArray->GetIsolate();
		v8::Local<v8::Context> context = isolate->GetCurrentContext();
		for (uint32_t i = 0; i < jsArray->Length(); ++i)
		{
#ifdef NODE_12
			vec.push_back((T)jsArray->Get(i)->NumberValue(context).ToChecked());
#elif defined ELECTRON_8
			vec.push_back((T)jsArray->Get(context,i).ToLocalChecked()->NumberValue());
#else
			vec.push_back((T)jsArray->Get(i)->NumberValue());
#endif
		}
		return true;
	}

	static std::vector<std::string> toCppStrVector(const v8::Local<v8::Value> &jsValue)
	{
		std::vector<std::string> vec;
		if (jsValue->IsUndefined() || !jsValue->IsArray())
			return vec;

		v8::Local<v8::Array> jsArray = v8::Local<v8::Array>::Cast(jsValue);
		v8::Isolate *isolate = jsArray->GetIsolate();
		for (uint32_t i = 0; i < jsArray->Length(); ++i)
		{
#ifdef ELECTRON_8
			v8::Local<v8::Context> context = isolate->GetCurrentContext();
			std::string str = toCppString(isolate, jsArray->Get(context,i).ToLocalChecked());
#else
			std::string str = toCppString(isolate, jsArray->Get(i));
#endif
			vec.push_back(std::move(str));
		}
		return vec;
	}
};
